package com.hqully.smartfumehood.common.websocket;

import com.github.pagehelper.PageInfo;
import com.google.gson.*;
import com.hqully.smartfumehood.common.enums.DeviceEnum;
import com.hqully.smartfumehood.common.utils.DecodeUtil;
import com.hqully.smartfumehood.common.utils.PermissionUtil;
import com.hqully.smartfumehood.common.utils.ResultVoUtil;
import com.hqully.smartfumehood.common.vo.QueryVo;
import com.hqully.smartfumehood.common.vo.ResultVo;
import com.hqully.smartfumehood.entity.AirData;
import com.hqully.smartfumehood.entity.FumeHoodData;
import com.hqully.smartfumehood.entity.SmokeData;
import com.hqully.smartfumehood.entity.dto.DevErrorDto;
import com.hqully.smartfumehood.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArraySet;

@Slf4j
@ServerEndpoint(value = "/UserWebSocket/{token}", encoders = {UserWebSocketEncoder.class}, decoders = {UserWebSocketDecoder.class})
@Component
public class UserWebSocketServer {
    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的WebSocket对象。
     */
    private static CopyOnWriteArraySet<UserWebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();

    /**
     * 与客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 接收识别码
     */
    private String token = "";

    static FumeHoodDataService fumeHoodDataService;

    @Autowired
    public void setFumeHoodDataService(FumeHoodDataService fumeHoodDataService){
        UserWebSocketServer.fumeHoodDataService = fumeHoodDataService;
    }

    static AirDataService airDataService;

    @Autowired
    public void setAirDataService(AirDataService airDataService){
        UserWebSocketServer.airDataService = airDataService;
    }

    static SmokeDataService smokeDataService;

    @Autowired
    public void setSmokeDataService(SmokeDataService smokeDataService){
        UserWebSocketServer.smokeDataService = smokeDataService;
    }

    static DeviceService deviceService;

    @Autowired
    public void setDeviceService(DeviceService deviceService){
        UserWebSocketServer.deviceService = deviceService;
    }

    private Gson gson = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
                @Override
                public JsonElement serialize(LocalDateTime localDateTime, Type type, JsonSerializationContext jsonSerializationContext) {
                    return new JsonPrimitive(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")));
                }
            })
            .serializeNulls()
            .create();


    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) {
        this.session = session;
        //如果存在就先删除一个，防止重复推送消息，实际这里实现了set，不删除问题也不大
        webSocketSet.removeIf(webSocket -> webSocket.token.equals(token));
        boolean add = webSocketSet.add(this);
        this.token = token;
        log.info("建立WebSocket连接，token：" + token+"，当前连接数："+webSocketSet.size());
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);
        log.info("关闭WebSocket连接，token：" + this.token +"，当前连接数："+webSocketSet.size());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到来[" + token + "]的信息:" + message);

        try {

            if ("device".equals(token)){
                if (!message.startsWith("z") && message.contains("z") && message.contains("q")){

                    HashMap<String, Object> fumeHoodDataMap = DecodeUtil.decodeFumeHoodData(message);

                    if (fumeHoodDataMap != null) {
                        FumeHoodData fumeHoodData = (FumeHoodData) fumeHoodDataMap.get("fumeHoodData");

                        fumeHoodDataService.addFumeHoodData(fumeHoodData);

                        if (!fumeHoodDataService.verifyFumeHoodData(fumeHoodData)) {

                            deviceService.updateDeviceStatusAndRecordById(DeviceEnum.DEVICE_STATUS_ERROR.getCode(),fumeHoodData.getVavId().toString(),fumeHoodData.getTime());
                        }else {

                            deviceService.updateDeviceStatusAndRecordById(fumeHoodData.getOpenCtrl(),fumeHoodData.getVavId().toString(),fumeHoodData.getTime());

                        }


                        sendToGroup(gson.toJson(fumeHoodData),"front");
                    }


                }else if (message.contains("a") && message.contains("s")){
                    HashMap<String, Object> airAndSmokeDataMap = DecodeUtil.decodeAirAndSmokeData(message);

                    if (airAndSmokeDataMap != null) {
                        AirData airData = (AirData) airAndSmokeDataMap.get("airData");

                        List<SmokeData> smokeDataList = (List<SmokeData>) airAndSmokeDataMap.get("smokeDataList");

                        airDataService.addAirData(airData);

                        smokeDataService.addSmokeDataGroup(smokeDataList);

                        sendToGroup(gson.toJson(airAndSmokeDataMap),"front");
                    }
                }
               sendTo(message,"user");

            }

            if ("user".equals(token)){
                sendMessage("发送成功");
                sendTo(message,"device");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("websocket发生错误",error);

    }

    /**
     * 实现服务器主动推送
     */
    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    private void sendResultVo(ResultVo resultVo) throws IOException {
        try {
            this.session.getBasicRemote().sendObject(resultVo);
        } catch (EncodeException e) {
            e.printStackTrace();
        }
    }



    static DevErrorService devErrorService  ;

    @Autowired
    public void setDevErrorService(DevErrorService devErrorService){
        UserWebSocketServer.devErrorService = devErrorService;
    }

    /**
     * 群发自定义消息
     */
    public void sendAll(String message) {
        log.info("推送消息到" + token + "，推送内容:" + message);
        for (UserWebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public void sendAllDevError(String message) {
        QueryVo queryVo = new QueryVo();
        log.info("推送消息到" + token + "，推送内容:" + message);
        PageInfo<DevErrorDto> allDevError = devErrorService.findAllDevError(queryVo);
        for (UserWebSocketServer item : webSocketSet) {
            try {
                item.sendResultVo(ResultVoUtil.success(allDevError));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendDevErrorSingle(String message, @PathParam("token") String token) {
        QueryVo queryVo = new QueryVo();
        Map map = new HashMap<String,Object>();
        queryVo.setQuery(map);
        log.info("推送消息到" + token + "，推送内容:" + message);
        QueryVo realQueryVo = PermissionUtil.setQueryUnitId(token, queryVo);
        PageInfo<DevErrorDto> allDevError = devErrorService.findAllDevError(realQueryVo);
        for (UserWebSocketServer item : webSocketSet) {
            try {
                if (item.token.equals(token)){
                    item.sendResultVo(ResultVoUtil.success(allDevError));

                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 定点推送
     */
    public void sendTo(String message, @PathParam("token") String token) {
        for (UserWebSocketServer item : webSocketSet) {
            try {
                if (item.token.equals(token)) {
                    log.info("推送消息到[" + token + "]，推送内容:" + message);
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public void sendToGroup(String message, @PathParam("token") String groupName) {
        for (UserWebSocketServer item : webSocketSet) {
            try {
                if (item.token.startsWith(groupName)) {
                    log.info("推送消息到组[" + item.token + "]，推送内容:" + message);
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        UserWebSocketServer that = (UserWebSocketServer) o;
        return Objects.equals(session, that.session) &&
                Objects.equals(token, that.token);
    }

    @Override
    public int hashCode() {
        return Objects.hash(session, token);
    }
}